﻿namespace Blaze.Editor.CLI
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Text;
    using EditorOnly;

    /// <summary>
    /// 提供svn命令的调用接口。
    /// </summary>
    public static class Svn
    {
        static Svn()
        {
#if UNITY_EDITOR_WIN
            try
            {
                var query = from path in Environment.GetEnvironmentVariable("Path").Split(';')
                    let target = Path.Combine(path, "svn.exe")
                    where File.Exists(target)
                    select target;
                mBinPath = query.FirstOrDefault();
            }
            catch
            {
                mBinPath = null;
            }

            if (mBinPath == null)
            {
                mBinPath = ProjectPath.Get("Tools/bin/svn/svn.exe");
                UnityEngine.Debug.LogWarning("[Svn]获取环境变量中的svn.exe失败，替代路径:" + mBinPath);
            }
#else
            mBinPath = "svn";
#endif
        }

        /// <summary>
        /// 从指定的仓库检出工作副本。
        /// </summary>
        /// <param name="url">仓库路径，如https://20.0.0.245/svn/UnityDMJ/trunk</param>
        /// <param name="path">目标路径，如C:\work\UnityDMJ</param>
        public static void Checkout(string url, string path)
        {
            var process = new Process
            {
                StartInfo =
                {
                    Arguments = $"--non-interactive checkout {url} \"{path}\"",
                    FileName = mBinPath,
                    UseShellExecute = false,
                    CreateNoWindow = false,
                    RedirectStandardOutput = false,
                    RedirectStandardError = false
                }
            };
            if (!process.Start())
                throw new ApplicationException("svn checkout failed");
            process.WaitForExit();
            var exitCode = process.ExitCode;
            if (exitCode != 0)
                throw new ApplicationException("svn checkout failed -> exit code=" + exitCode);
        }

        /// <summary>
        /// 查询最新版本信息
        /// </summary>
        /// <returns></returns>
        public static SvnInfo Info(string path)
        {
            var process = new Process
            {
                StartInfo =
                {
                    FileName = mBinPath,
                    Arguments = $"info \"{path}\"",
                    StandardOutputEncoding = Encoding.GetEncoding("GB2312"),
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true
                }
            };

            var success = process.Start();
            if (!success)
                throw new Exception("run svn info failed.");
            var result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return SvnInfo.Parse(result);
        }

        /// <summary>
        /// 还原指定的工作副本。
        /// </summary>
        /// <param name="path">工作副本完整路径</param>
        public static void Revert(string path)
        {
            var isDir = File.GetAttributes(path).HasFlag(FileAttributes.Directory);
            var process = new Process
            {
                StartInfo =
                {
                    Arguments = $"--non-interactive {(isDir ? "-R " : string.Empty)} revert \"{path}\"",
                    FileName = mBinPath,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = false,
                    RedirectStandardError = false
                }
            };
            if (!process.Start())
                throw new ApplicationException("svn revert failed -> " + path);
            process.WaitForExit();
            var exitCode = process.ExitCode;
            if (exitCode != 0)
                throw new ApplicationException("svn revert failed -> exit code=" + exitCode);
        }

        /// <summary>
        /// 查询指定工作副本的状态。
        /// </summary>
        /// <param name="path">路径</param>
        public static StatusInfo Status(string path)
        {
            var process = new Process
            {
                StartInfo =
                {
                    FileName = mBinPath,
                    Arguments = $"status \"{path}\"",
                    StandardOutputEncoding = Encoding.GetEncoding("GB2312"),
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    RedirectStandardOutput = true
                }
            };

            var success = process.Start();
            if (!success)
                throw new Exception("run svn status failed.");
            var result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return StatusInfo.Parse(result);
        }

        /// <summary>
        /// 更新指定的工作副本。
        /// </summary>
        /// <param name="path">工作副本完整路径</param>
        public static void Update(string path)
        {
            var process = new Process
            {
                StartInfo =
                {
                    Arguments = $"--non-interactive update \"{path}\"",
                    FileName = mBinPath,
                    UseShellExecute = false,
                    CreateNoWindow = false,
                    RedirectStandardOutput = false,
                    RedirectStandardError = false
                }
            };
            if (!process.Start())
                throw new ApplicationException("svn update failed -> " + path);
            process.WaitForExit();
            var exitCode = process.ExitCode;
            if (exitCode != 0)
                throw new ApplicationException("svn update failed -> exit code=" + exitCode);
        }

        private static readonly string mBinPath;
    }
}